package com.lyy.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lyy.component.PointsTask;
import com.lyy.entity.*;
import com.lyy.mapper.OrderDetailMapper;
import com.lyy.mapper.OrderMapper;
import com.lyy.mapper.UserMapper;
import com.lyy.mapper.VideoMapper;

import com.lyy.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;


@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private VideoMapper videoMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private PointsTask pointsTask;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Order buy(Order order, Integer userId, Integer[] videoIds) {

        // DB: 按 [用户表主键] 查询一条 [用户]
        User user = userMapper.selectByUserId(userId);
        if (ObjectUtil.isNull(user)) {
            log.error("下单失败: 用户主键 {} 不存在 ", userId);
            throw new RuntimeException("用户不存在");
        }

        // DB: 按 [视频表主键数组] 查询 [视频]
        List<Video> videos = videoMapper.selectByVideoIds(videoIds);
        if (ObjectUtil.isEmpty(videos) || videos.size() < videoIds.length) {
            log.error("下单失败: 视频主键 {} 中，至少一个不存在", Arrays.toString(videoIds));
            throw new RuntimeException("视频不存在");
        }

        // DB: 按 [用户表主键] 查询 [用户明细]
        OrderDetail orderDetailCondition = new OrderDetail();
        orderDetailCondition.setFkUserId(userId);
        List<OrderDetail> orderDetails = orderDetailMapper.selectDetail(orderDetailCondition);

        // 校验 [用户] 是否重复购买任一 [视频]
        for (Integer videoId : videoIds) {
            for (OrderDetail orderDetail : orderDetails) {
                if (orderDetail.getFkVideoId().equals(videoId)) {
                    log.error("下单失败: 视频主键 {} 中，至少一个已购买", Arrays.toString(videoIds));
                    throw new RuntimeException("视频重复购买");
                }
            }
        }

        // 构建 [订单] 实体
        order.setOrderNumber(RandomUtil.randomNumbers(19));
        order.setOrderId(null);
        order.setOrderInfo(null == order.getOrderInfo() ? "暂无订单信息" : order.getOrderInfo());
        order.setCreateTime(new Date().getTime());
        order.setModifyTime(new Date().getTime());

        // DB: 添加一条 [订单]
        if (orderMapper.insert(order) <= 0) {
            log.error("下单失败: 订单表数据库记录添加失败");
            throw new RuntimeException("订单添加失败");
        }

        // DB: 循环添加 [订单明细]
        for (Integer videoId : videoIds) {

            // 构建 [订单明细] 实体
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setFkVideoId(videoId);
            orderDetail.setFkOrderId(order.getOrderId());
            orderDetail.setFkUserId(userId);
            orderDetail.setCreateTime(new Date().getTime());
            orderDetail.setModifyTime(new Date().getTime());

            // DB: 添加 [订单明细]，若添加失败则抛出异常触发回滚
            if (orderDetailMapper.insert(orderDetail) <= 0) {
                log.error("下单失败: 订单明细表数据库记录添加失败");
                throw new RuntimeException("订单明细添加失败");
            }
        }

        // 下单成功后为用户异步添加积分
        this.addPoints(userId, order.getTotalFee());

        return order;
    }

    private void addPoints(Integer userId,double totalFee){
        Future<String>future=pointsTask.addPoints(userId,totalFee);
        while (true){
            try{
                if (future.isDone()){
                    break;
                }
            }catch (Exception e){
                throw  new RuntimeException("异步添加积分异常");
            }
        }
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteByOrderId(Integer orderId) {

        Order orderCondition;
        OrderDetail videoOrderCondition;

        // DB: 按订单表主键查询一条订单记录
        orderCondition = new Order();
        orderCondition.setOrderId(orderId);
        List<Order> orders = orderMapper.select(orderCondition);
        if (ObjectUtil.isEmpty(orders)) {
            throw new RuntimeException("查询失败: 订单表主键不存在");
        }

        // DB: 按订单表主键删除视频订单中间表记录
        videoOrderCondition = new OrderDetail();
        videoOrderCondition.setFkOrderId(orderId);
        if (orderDetailMapper.delete(videoOrderCondition) <= 0) {
            throw new RuntimeException("视频订单中间表删除失败: 未知原因");
        }

        // DB: 按订单表主键删除一条订单记录
        orderCondition = new Order();
        orderCondition.setOrderId(orderId);
        if (orderMapper.delete(orderCondition) <= 0) {
            throw new RuntimeException("订单删除失败: 未知原因");
        }
    }
    @Override
    public PageInfo<OrderDetail> pageOrderDetail(Integer pageNum, Integer pageSize, Integer userId) {

        // DB: 按 [用户表主键] 分页查询 [订单明细]
        OrderDetail orderDetailCondition = new OrderDetail();
        orderDetailCondition.setFkUserId(userId);
        PageHelper.startPage(pageNum, pageSize);
        List<OrderDetail> orderDetails = orderDetailMapper.selectDetail(orderDetailCondition);
        // 封装分页结果并返回
        return new PageInfo<>(orderDetails);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteOrderDetail(Integer orderDetailId) {

        // DB: 按 [订单明细表主键] 查询一条 [订单明细]
        OrderDetail condition = new OrderDetail();
        condition.setOrderDetailId(orderDetailId);
        List<OrderDetail> orderDetails = orderDetailMapper.selectDetail(condition);
        if (ObjectUtil.isEmpty(orderDetails)) {
            log.error("订单明细删除失败: 订单明细表主键 {} 不存在", orderDetailId);
            throw new RuntimeException("订单明细不存在");
        }
        OrderDetail orderDetail = orderDetails.get(0);

        // DB: 按 [订单明细表主键] 删除一条 [订单明细]

        condition = new OrderDetail();
        condition.setOrderDetailId(orderDetailId);
        if (orderDetailMapper.delete(condition) <= 0) {
            log.error("订单明细删除失败: 订单明细表数据库记录删除失败");
            throw new RuntimeException("订单明细删除失败");
        }

        // DB: 按 [订单表主键] 查询 [订单明细] 记录
        Integer orderId = orderDetail.getFkOrderId();
        OrderDetail orderDetailCondition = new OrderDetail();
        orderDetailCondition.setFkOrderId(orderId);
        orderDetails = orderDetailMapper.selectDetail(orderDetailCondition);

        // 若查询结果为空说明该订单已不存在任何关联的中间表记录，可删除
        if (ObjectUtil.isEmpty(orderDetails)) {
            // DB: 按 [订单表主键] 删除一条 [订单]
            Order orderCondition = new Order();
            orderCondition.setOrderId(orderId);
            if (orderMapper.delete(orderCondition) <= 0) {
                log.error("订单明细删除失败: 订单表数据库记录删除失败");
                throw new RuntimeException("订单表删除失败");
            }
        }
    }
}
